package com.supreme.uploadserver.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.supreme.uploadserver.service.IHttpService;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class HttpReqService<PT> implements IHttpService<HttpReqService<PT>> {

    /**
     * GET POST PUT DELETE
     */
    private String method;

    private String url;

    private String endpoint;

    private String path;

    private List<NameValuePair> query;

    private JSONObject body;

    private String uploadKey;

    private String uploadFile;

    public HttpReqService() {
        this.method = IHttpService.GET_METHOD;
        this.query = new ArrayList<>();
    }

    public HttpReqService<PT> getReq() {
        return this.setMethod(IHttpService.GET_METHOD);
    }

    public HttpReqService<PT> postReq() {
        return this.setMethod(IHttpService.POST_METHOD);
    }

    public HttpReqService<PT> putReq() {
        return this.setMethod(IHttpService.PUT_METHOD);
    }

    public HttpReqService<PT> deleteReq() {
        return this.setMethod(IHttpService.DELETE_METHOD);
    }

    public HttpReqService<PT> uploadReq() {
        return this.setMethod(IHttpService.UPLOAD_METHOD);
    }

    @Override
    public HttpReqService<PT> setMethod(String method) {
        this.method = method;
        return this;
    }

    @Override
    public HttpReqService<PT> setUrl(String url) {
        this.url = url;
        return this;
    }

    public String getUrl() {
        return url;
    }

    @Override
    public HttpReqService<PT> setEndpoint(String endpoint) {
        this.endpoint = endpoint;
        return this;
    }

    public String getEndpoint() {
        return endpoint;
    }

    @Override
    public HttpReqService<PT> setPath(String path) {
        this.path = path;
        return this;
    }

    public String getPath() {
        return path;
    }

    @Override
    public HttpReqService<PT> setQuery(List<NameValuePair> query) {
        this.query = query;
        return this;
    }

    @Override
    public HttpReqService<PT> setQuery(Map<String, String> query) {
        Set<Map.Entry<String, String>> entries = query.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            BasicNameValuePair basicNameValuePair = new BasicNameValuePair(entry.getKey(), entry.getValue());
            this.query.add(basicNameValuePair);
        }
        return this;
    }

    @Override
    public HttpReqService<PT> setQuery(JSONObject query) {
        query.forEach((key, val) -> {
            BasicNameValuePair basicNameValuePair = new BasicNameValuePair(key, String.valueOf(val));
            this.query.add(basicNameValuePair);
        });
        return this;
    }

    public List<NameValuePair> getQuery() {
        return query;
    }

    @Override
    public HttpReqService<PT> setBody(JSONObject body) {
        this.body = body;
        return this;
    }

    public JSONObject getBody() {
        return body;
    }

    public HttpReqService<PT> addUploadFile(String uploadFile) {
        this.uploadKey = "file";
        this.uploadFile = uploadFile;
        return this;
    }

    public HttpReqService<PT> addUploadFile(String uploadKey, String uploadFile) {
        this.uploadKey = uploadKey;
        this.uploadFile = uploadFile;
        return this;
    }

    @Override
    public JSONObject request() {
        JSONObject respResult = null;

        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();

        // 响应模型
        CloseableHttpResponse response = null;

        try {
            // 创建URI对象，并且设置请求参数
            StringBuilder requestUrl = new StringBuilder();
            if (!StringUtils.isBlank(this.url)) {
                requestUrl.append(this.url);
            } else {
                requestUrl.append(this.endpoint);
                if (!StringUtils.isBlank(this.path)) {
                    requestUrl.append("/");
                    requestUrl.append(this.path);
                }
            }

            URI uri = new URIBuilder(String.valueOf(requestUrl))
                    .setParameters(query)
                    .build();
            System.out.println(uri.toString());

            if (this.method.equals(IHttpService.POST_METHOD)) {
                HttpPost httpPost = new HttpPost(uri);

                if (body != null) {
                    StringEntity stringEntity = new StringEntity(body.toString(), StandardCharsets.UTF_8);
                    httpPost.setEntity(stringEntity);
                }

                response = httpClient.execute(httpPost);
            } else if (this.method.equals(IHttpService.UPLOAD_METHOD)) {
                HttpPost httpPost = new HttpPost(uri);

                Path uploadFilePath = Paths.get(this.uploadFile);
                if (!Files.exists(uploadFilePath)) {
                    throw new FileNotFoundException();
                }

                File uploadFile = uploadFilePath.toFile();
                MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
                String filename = uploadFilePath.getFileName().toString();
                multipartEntityBuilder.addBinaryBody(this.uploadKey, uploadFile, ContentType.MULTIPART_FORM_DATA, filename);
                multipartEntityBuilder.addTextBody("filename", filename, ContentType.TEXT_PLAIN);

                HttpEntity reqEntity = multipartEntityBuilder.build();
                httpPost.setEntity(reqEntity);

                response = httpClient.execute(httpPost);
            } else {
                HttpGet httpGet = new HttpGet(uri);
                response = httpClient.execute(httpGet);
            }

            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                // 解析响应数据
                String content = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
                respResult = JSONObject.parseObject(content);
            }
        } catch (URISyntaxException | IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 释放资源
                if (response != null) {
                    response.close();
                }
                if (httpClient != null) {
                    httpClient.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return respResult;
    }
}
